﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Algoritmia.DataStructures.Queues
{
    public class Lifo<T> : ILifo<T>
    {
        private readonly Lists.IList<T> _list;

        public Lifo( IEnumerable<T> items=null, Func<IEnumerable<T>,Lists.IList<T>> createList=null)
        {
            items = items ?? Enumerable.Empty<T>();
            createList = createList ?? (v => new Lists.LinkedList<T>(v));
            _list = createList(items);
        }

        public T this[int index]
        {
            get { return _list[index]; }
        }

        #region IQueue<T> Members

        public virtual void Push(T elem)
        {
            _list.Add(elem);
        }

        public T Pop()
        {
            if (_list.Count == 0)
            {
                throw new InvalidOperationException("Lifo queue is empty.\r\nAdd an element to pop any element");
            }
            T value = _list[_list.Count - 1];
            _list.RemoveAt(_list.Count - 1);
            return value;

        }

        public virtual T Top()
        {
            if (_list.Count == 0)
            {
                throw new InvalidOperationException("Lifo queue is empty.\r\nAdd an element to take the element on the top.");
            }
            return _list[_list.Count-1];
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            for (int i = _list.Count - 1; i >= 0; i--)
                yield return _list[i];
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        #region ICountable Members

        public virtual int Count
        {
            get { return _list.Count; }
        }

        #endregion

        public override string ToString()
        {
            return String.Format("{0} <{1}> [{2}] ", GetType().Name, typeof(T).Name, string.Join(",",this));
        }
    }
}
